package hxy.ecnu.handler;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;

import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import hxy.ecnu.model.BaseException;
import hxy.ecnu.model.BaseResponse;
import lombok.extern.slf4j.Slf4j;

@ControllerAdvice
@Slf4j
@ResponseBody
public class GlobalExceptionHandler {

    /**
     * 业务异常捕获
     *
     * @param request
     * @param e
     * @param <T>
     * @return
     */
    @ExceptionHandler(BaseException.class)
    public <T> BaseResponse<?> baseExcepitonHandler(HttpServletRequest request, BaseException e) {
//        e.printStackTrace();
        log.error("{} Exception", request.getRequestURI(), e.getMessage(), e);
        return BaseResponse.error("出错啦！", e.getMessage());
    }

    /**
     * 参数校验异常捕获
     *
     * @param request
     * @param e
     * @param <T>
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public <T> BaseResponse<?> constraintViolationExceptionHandler(HttpServletRequest request, ConstraintViolationException e) {
        log.error("{} Exception", request.getRequestURI(), e.getMessage(), e);
        return BaseResponse.error("出错啦！", e.getMessage());
    }


    /**
     * 处理异常的访问链接
     *
     * @param e
     * @param webRequest
     * @return
     */
    @ExceptionHandler(value = {NoHandlerFoundException.class})
    public ModelAndView noMappingHandler(Exception e, WebRequest webRequest) {
        log.error("No mapping exception:{}", e.getMessage(), e);
        ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
        modelAndView.addObject("code", 404);
        modelAndView.addObject("msg", "接口异常，详情查询服务端");
        modelAndView.addObject("data", e.getMessage());
        return modelAndView;
    }

    /**
     * 处理400参数错误
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public BaseResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        log.error("参数解析失败", e);
        return new BaseResponse(400, "参数解析失败", e.getMessage());
    }

    /**405错误方法不支持
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public BaseResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error("不支持当前请求方法", e);
        return new BaseResponse(405,"请求方法不支持","request_method_not_supported");
    }

    /**
     * 这个应该放在最下面比较好，最后加载
     * 处理未定义的其他异常信息
     * 参数为空等
     *
     * @param request
     * @param exception
     * @return
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public BaseResponse exceptionHandler(HttpServletRequest request, Exception exception) {
        String message = exception.getMessage();
        log.error("{} Exception Message: {}", request.getRequestURI(), message, exception);

        if (exception instanceof NullPointerException) {
            message = "biu，踩雷啦！";
        } else if (exception instanceof ValidationException) {
            message = "参数检验出错啦！";
        } else if (exception instanceof BaseException) {
            message = "业务处理发生错误";
        }

        return BaseResponse.error(message, exception.getMessage());
    }
}
